# -*- coding: utf-8 -*-
from __future__ import print_function, division
#系统库
import traceback
#第三方库

#自定义库
import Serverlib
import local
import auth
import account
import game
import Mods


#主体
logger = Serverlib.logging.getLogger('SERVER')


class GameHall(object):
    def __init__(self):
        self.player_map = {}
        self.username_map = {}
        self.socket_map = {}
        self.rooms = {}
        Mods.load()

    def player_login(self, username, passwd):
        userinfo, code, errormsg = auth.login(username, passwd)
        if code != 0 or userinfo == None:
            return 0, code, errormsg
        if userinfo['u_id'] in self.player_map:
            if self.player_map[userinfo['u_id']].state == account.User.US_LOST:
                room = self.player_map[userinfo['u_id']].current_room
                if room and room.state == Room.RS_GAMING:
                    self.player_map[userinfo['u_id']].state = account.User.US_GAMING
                else:
                    self.player_map[userinfo['u_id']].state == account.User.US_NORMAL
            logger.debug("[{0}]: reconnected".format(userinfo['u_id']))
            return userinfo['u_id'], code, errormsg
        player = account.User(userinfo['u_id'], userinfo['username'])
        self.player_map[userinfo['u_id']] = player
        logger.debug("[{0}]: join the hall".format(userinfo['u_id']))
        return userinfo['u_id'], code, errormsg

    def player_logout(self, u_id):
        player = self.player_map.get(u_id)
        if player == None:
            return 10003, local.String.HL_ER_usernotexist
        if player.current_room != None:
            if player.current_room.state != Room.RS_NORMAL:
                return 10004, local.String.HL_ER_userinroom
            code, errormsg = self.exit_room(u_id)
            if code != 0:
                return code, errormsg
        self.player_map.pop(u_id)
        logger.debug("[{0}]: leaving the hall".format(u_id))
        return 0, ""

    def player_ready(self, u_id):
        player = self.player_map.get(u_id)
        if player == None:
            return 10005, local.String.HL_ER_usernotexist
        if player.current_room == None:
            return 10006, local.String.HL_ER_notinroom
        errormsg = player.current_room.ready(player)
        if errormsg:
            return 10007, errormsg
        return 0, ""

    def lost_connection(self, u_id):
        player = self.player_map.get(u_id)
        if player == None:
            return
        logger.debug("[{0}]: lost connection".format(u_id))
        if player.state != account.User.US_GAMING:
            self.player_logout(u_id)
            return
        else:
            player.state = account.User.US_LOST
            player.current_room.lost(player)
            pass

    def create_room(self, u_id, name, passwd=None):
        player = self.player_map.get(u_id)
        if player == None:
            return 10008, local.String.HL_ER_usernotexist
        if name == None or len(name) == 0:
            return 10009, local.String.HL_ER_invalidname
        if player.current_room != None or player.state == account.User.US_GAMING:
            return 10010, local.String.HL_ER_userinroom
        room = Room(name, passwd)
        if name in self.rooms:
            if self.rooms[name].state != Room.RS_DESTROY:
                return 10011, local.String.HL_ER_nameduplicate
        errormsg = room.join(player, passwd)
        if errormsg:
            return 10012, errormsg
        room.creater = u_id
        room.passwd = passwd
        self.rooms[name] = room
        return 0, ""

    def join_room(self, u_id, name, passwd=None):
        player = self.player_map.get(u_id)
        if player == None:
            return 10013, local.String.HL_ER_usernotexist
        room = self.rooms.get(name)
        if room == None or room.state == Room.RS_DESTROY:
            return 10014, local.String.HL_ER_roomnotexist
        if player.current_room == room:
            return 10025, local.String.RM_ER_alreadyin
        if player.current_room:
            errormsg = player.current_room.exit(player)
            if errormsg:
                return 10015, errormsg
        errormsg = room.join(player, passwd)
        if errormsg:
            return 10016, errormsg
        else:
            return 0, ""

    def exit_room(self, u_id):
        player = self.player_map.get(u_id)
        if player == None:
            return 10017, local.String.HL_ER_usernotexist
        if player.current_room:
            errormsg = player.current_room.exit(player)
            if errormsg:
                return 10018, errormsg
            return 0, ""
        else:
            return 10019, local.String.HL_ER_usernotinroom

    def game_start(self, u_id):
        player = self.player_map.get(u_id)
        if player == None:
            return 10020, local.String.HL_ER_usernotexist
        if player.current_room:
            errormsg = player.current_room.start(player)
            if errormsg:
                return 10021, errormsg
            return 0, ""
        else:
            return 10022, local.String.HL_ER_usernotinroom

    def get_room_list(self):
        roomlist = self.rooms.values()
        retlist = []
        for item in roomlist:
            if item.state != Room.RS_DESTROY:
                retlist.append(item.name)
        return retlist

    def get_room_info(self, name):
        room = self.rooms.get(name)
        if room == None:
            return None, 10023, local.String.HL_ER_roomnotexist
        if room.state == Room.RS_DESTROY:
            return None, 10024, local.String.HL_ER_roomnotexist
        retdata = room.get_info()
        return retdata, 0, ""

    def get_game_info(self, u_id=None):
        player = self.player_map.get(u_id)
        room = player.current_room
        if room == None:
            return None, 10026, local.String.HL_ER_gamenotexist
        if room.state != Room.RS_GAMING:
            return None, 10027, local.String.HL_ER_gamenotexist
        retdata = room.get_game_info(player)
        return retdata, 0, ""

    def get_logon_player(self, u_id):
        return self.player_map.get(u_id)


class Room(object):
    RS_NORMAL = 0
    RS_GAMING = 1
    RS_DESTROY = 2
    RS_STATESTRING = [
        local.String.RM_RS_normal,
        local.String.RM_RS_gaming,
        local.String.RM_RS_destroy
        ]

    def __init__(self, name, passwd=None):
        self.name = name
        self.passwd = passwd
        self.maxseat = 2
        self.players = {}
        self.creater = None
        self.owner = None
        self.game = None
        self.state = Room.RS_NORMAL
        logger.debug("<{0}>: room created".format(self.name))
        return None

    def destroy(self):
        if len(self.players) > 0:
            return local.String.RM_ER_gotplayers
        if self.game != None:
            self.game.destroy()
            self.game = None
        self.state = Room.RS_DESTROY
        logger.debug("<{0}>: room destroyed".format(self.name))
        return None

    def room_error(self, error):
        logger.debug("<{0}>: game error: {1}".format(self.name, error))
        if len(self.players) > 0:
            errormsg = dict(
                code=5,
                room=self.name
                )
            for player_in_room in self.players.values():
                if player_in_room.state != account.User.US_LOST:
                    player_in_room.state = account.User.US_NORMAL
                    player_in_room.current_room = None
                    player_in_room.comet.sent(errormsg)
            self.players = {}
        self.destroy()

    def get_info(self):
        retdata = dict(
            name=self.name,
            passwd=(self.passwd != None),
            maxseat=self.maxseat,
            state=Room.RS_STATESTRING[self.state]
            )
        owner = self.players.get(self.owner)
        if owner != None:
            retdata['owner'] = owner.username
        ready = []
        notready = []
        for u_id in self.players:
            if self.players[u_id].state == account.User.US_READY:
                ready.append(self.players[u_id].username)
            else:
                notready.append(self.players[u_id].username)
        retdata['ready'] = ready
        retdata['notready'] = notready
        return retdata

    def get_game_info(self, player=None):
        if self.game == None:
            return local.String.RM_ER_gamenotexist
        params = dict(
            u_id=player.u_id
            )
        retdata = self.game.call_func('format_gamedata', params)
        return retdata

    def join(self, player, passwd=None):
        if passwd != self.passwd:
            return local.String.RM_ER_passwderror
        if player.u_id in self.players:
            return local.String.RM_ER_alreadyin
        if len(self.players) == self.maxseat:
            return local.String.RM_ER_roomfull
        if player.current_room != None:
            return local.String.RM_ER_inanotherroom
        #发送信息给房间内的人
        joinmessage = dict(
            code=1,
            room=self.name,
            username=player.username
            )
        for player_in_room in self.players.values():
            if player_in_room.state != account.User.US_LOST:
                player_in_room.comet.sent(joinmessage)
        #人加入房间
        self.players[player.u_id] = player
        if self.owner == None:
            self.owner = player.u_id
        player.current_room = self
        logger.debug("[{0}] joined the room <{1}>".format(player.u_id, self.name))
        return None

    def ready(self, player):
        if player.u_id not in self.players:
            return local.String.RM_ER_notin
        if self.state != Room.RS_NORMAL:
            return local.String.RM_RS_gaming
        errormsg = ""
        if player.state == account.User.US_NORMAL:
            player.state = account.User.US_READY
            errormsg = local.String.RM_US_TOREADY
            logger.debug("[{0}] ready".format(player.u_id))
        elif player.state == account.User.US_READY:
            player.state = account.User.US_NORMAL
            errormsg = local.String.RM_US_TONORMAL
            logger.debug("[{0}] cancel ready".format(player.u_id))
        #发送准备消息
        readymessage = dict(
            code=3,
            username=player.username,
            msg=errormsg
            )
        for player_in_room in self.players.values():
            if player_in_room.state != account.User.US_LOST:
                player_in_room.comet.sent(readymessage)
        return None

    def lost(self, player):
        pass

    def exit(self, player):
        if player.u_id not in self.players:
            return local.String.RM_ER_notin
        if self.state != Room.RS_NORMAL or player.state == account.User.US_GAMING or player.state == account.User.US_LOST:
            return local.String.RM_ER_cantquit
        player.current_room = None
        del(self.players[player.u_id])
        #发送离线消息
        leavemessage = dict(
            code=2,
            room=self.name,
            username=player.username
            )
        for player_in_room in self.players.values():
            if player_in_room.state != account.User.US_LOST:
                player_in_room.comet.sent(leavemessage)
        logger.debug("[{0}] left the room <{1}>".format(player.u_id, self.name))
        #准备销毁房间
        if len(self.players) == 0:
            self.destroy()
        elif self.owner == player.u_id:
            self.owner = self.players.values()[0].u_id
        return None

    def start(self, player):
        if player.u_id not in self.players:
            return local.String.RM_ER_notin
        if player.u_id != self.owner:
            return local.String.RM_ER_notowner
        if self.state != Room.RS_NORMAL:
            return local.String.RM_ER_cantstart
        for player_in_room in self.players.values():
            if player_in_room.state != account.User.US_READY:
                return local.String.RM_ER_cantstart
        #发送消息
        startmessage = dict(
            code=4,
            room=self.name,
            )
        for player_in_room in self.players.values():
            if player_in_room.state != account.User.US_LOST:
                player_in_room.comet.sent(startmessage)
        logger.debug("<{0}> game start".format(self.name))
        #start game
        self.state = Room.RS_GAMING
        self.game = game.FSM(self)
        logger.debug("<{0}> start a game".format(self.name))
        try:
            self.game.on_event('game_start', None)
        except Exception, e:
            self.room_error(e)
            print(traceback.format_exc())
        return None

gamehall = GameHall()
